/*
 * Copyright 2024, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 */

#include <KernelExport.h>
#include <PCI.h>
#include <malloc.h>
#include <string.h>

#include "loongarch_vesa_private.h"

#define TRACE_DRIVER
#ifdef TRACE_DRIVER
#define TRACE(x...) dprintf(DRIVER_PREFIX ": " x)
#else
#define TRACE(x...) ;
#endif

#define ERROR(x...) dprintf(DRIVER_PREFIX ": " x)

// 全局变量
int32 api_version = B_CUR_DRIVER_API_VERSION;
pci_module_info *gPCI;
static device_info *gDeviceInfo[MAX_LOONGARCH_VESA_DEVICES];
char *gDeviceNames[MAX_LOONGARCH_VESA_DEVICES + 1];

// 查找支持的设备
static status_t
probe_devices()
{
    TRACE("probe_devices()\n");

    // 初始化设备列表
    for (int32 i = 0; i < MAX_LOONGARCH_VESA_DEVICES; i++)
    {
        gDeviceInfo[i] = NULL;
        gDeviceNames[i] = NULL;
    }
    gDeviceNames[MAX_LOONGARCH_VESA_DEVICES] = NULL;

    // 获取PCI总线管理器
    if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI) != B_OK)
    {
        ERROR("Failed to get PCI module\n");
        return B_ERROR;
    }

    // 查找龙芯显示控制器
    int32 index = 0;
    pci_info info;
    for (int32 i = 0; gPCI->get_nth_pci_info(i, &info) == B_OK; i++)
    {
        // 检查是否是显示控制器
        if (info.class_base != PCI_display)
        {
            continue;
        }

        // 检查是否是龙芯显示控制器
        // 龙芯7A2000的PCI ID: 0x0014:0x7a06
        if (info.vendor_id == 0x0014 && info.device_id == 0x7a06)
        {
            TRACE("Found LoongArch display controller at %u:%u:%u\n",
                  info.bus, info.device, info.function);

            // 分配设备信息结构
            device_info *di = (device_info *)malloc(sizeof(device_info));
            if (di == NULL)
            {
                ERROR("Failed to allocate device_info\n");
                continue;
            }

            // 初始化设备信息
            memset(di, 0, sizeof(device_info));
            di->pcii = info;
            di->handle = index;

            // 分配设备名称
            char name[B_OS_NAME_LENGTH];
            sprintf(name, DEVICE_FORMAT,
                    info.vendor_id, info.device_id,
                    info.bus, info.device, info.function);

            gDeviceNames[index] = strdup(name);
            if (gDeviceNames[index] == NULL)
            {
                ERROR("Failed to allocate device name\n");
                free(di);
                continue;
            }

            // 初始化设备
            if (device_init(di) != B_OK)
            {
                ERROR("Failed to initialize device\n");
                free(gDeviceNames[index]);
                free(di);
                continue;
            }

            // 添加到设备列表
            gDeviceInfo[index++] = di;

            // 检查是否已达到最大设备数
            if (index >= MAX_LOONGARCH_VESA_DEVICES)
                break;
        }
    }

    TRACE("Found %ld devices\n", index);

    // 如果没有找到设备，释放PCI模块
    if (index == 0)
    {
        put_module(B_PCI_MODULE_NAME);
        return B_ERROR;
    }

    return B_OK;
}

// 初始化驱动程序
status_t
init_driver(void)
{
    TRACE("init_driver()\n");

    // 查找设备
    status_t status = probe_devices();
    if (status != B_OK)
    {
        ERROR("No devices found\n");
        return status;
    }

    return B_OK;
}

// 卸载驱动程序
void uninit_driver(void)
{
    TRACE("uninit_driver()\n");

    // 释放设备资源
    for (int32 i = 0; i < MAX_LOONGARCH_VESA_DEVICES; i++)
    {
        if (gDeviceInfo[i])
        {
            device_uninit(gDeviceInfo[i]);
            free(gDeviceInfo[i]);
            gDeviceInfo[i] = NULL;
        }
        if (gDeviceNames[i])
        {
            free(gDeviceNames[i]);
            gDeviceNames[i] = NULL;
        }
    }

    // 释放PCI模块
    put_module(B_PCI_MODULE_NAME);
}

// 发布设备
const char **
publish_devices(void)
{
    TRACE("publish_devices()\n");
    return (const char **)gDeviceNames;
}

// 查找设备
device_hooks *
find_device(const char *name)
{
    TRACE("find_device(%s)\n", name);
    return &gDeviceHooks;
}